﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace DarkAngels.WoW.Library.Armory.Character.tabs
{
    public class AchievementTab : AbstractDataClass
    {
        private const string XPATH_ACHIEVEMENT_ROOTCATEGORIES = "/page/achievements/rootCategories/category";
        private const string XPATH_ACHIEVEMENT_SUMMARY = "/page/achievements/summary/c";
        private const string XPATH_CHARACTER_BASIC_INFO_NODE = "/page/characterInfo/character";

        private Character m_char = null;
        public AchievementTab(Character character)
        {
            m_char = character;
        }
        public override void Load()
        {
            LoadData();
        }

        private void LoadData()
        {
            XmlData = Character.Provider.GetFile(BuildUri(FileName));
            if (!Character._Loaded)
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(XmlData);
                XmlNode characterInfo = xmlDoc.SelectSingleNode(XPATH_CHARACTER_BASIC_INFO_NODE);
                Character._SetProperties(characterInfo);
            }
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(XmlData);
            XmlNode overallSummary = xml.SelectSingleNode(XPATH_ACHIEVEMENT_SUMMARY);
            AchievementsTotal = Int32.Parse(overallSummary.Attributes["total"].Value);
            AchievementsEarned = Int32.Parse(overallSummary.Attributes["earned"].Value);
            PointsTotal = Int32.Parse(overallSummary.Attributes["totalPoints"].Value);
            PointsEarned = Int32.Parse(overallSummary.Attributes["points"].Value);
            XmlNodeList categories = xml.SelectNodes(XPATH_ACHIEVEMENT_ROOTCATEGORIES);
            foreach (XmlNode rootCategory in categories)
            {
                AchievementsCategory category = new AchievementsCategory(rootCategory, BuildUri(FileName));
                category.Provider = Character.Provider;
                category.Load();
                m_categories.Add(category);
            }
        }

        public Character Character
        {
            get
            {
                return m_char;
            }
        }
        private String XmlData
        {
            get;
            set;
        }
        private String FileName
        {
            get
            {
                if (Character._Loaded)
                    return String.Format("character-achievements.xml?{0}", Character.CharUrl);
                else
                    return String.Format("character-achievements.xml?r={0}&n={1}", Character.RealmName, Character.CharacterName);
            }
        }
        private int m_total = 0;
        public Int32 AchievementsTotal
        {
            get
            {
                return m_total;
            }
            set
            {
                m_total = value;
            }
        }
        public Int32 AchievementsEarned
        {
            get;
            private set;
        }
        public Int32 PointsTotal
        {
            get;
            private set;
        }
        public Int32 PointsEarned
        {
            get;
            private set;
        }
        private List<AchievementsCategory> m_categories = new List<AchievementsCategory>();
        public List<AchievementsCategory> Categories
        {
            get
            {
                return m_categories;
            }
        }
    }

    public class AchievementsCategory : AbstractDataClass
    {
        private const string XPATH_ACHIEVEMENT_CATEGORIES = "/achievements/category/category";
        private const string XPATH_ACHIEVEMENT_ROOT_ACHIEVEMENTS = "/achievements/category/achievement";
        private const string XPATH_ACHIEVEMENT_CATEGORY_TITLES = "./category";
        private const string XPATH_ACHIEVEMENT_SUBCATEGORY_ACHIEVEMENTS = "./achievement";
        private string m_filename = null;
        private XmlNode m_data = null;
        private XmlNode m_data2 = null;

        public AchievementsCategory(XmlNode data, String filename)
        {
            m_data = data;
            m_filename = filename;
        }
        public AchievementsCategory(XmlNode data, XmlNode data2)
        {
            m_data = data;
            m_data2 = data2;
        }

        public override void Load()
        {
            Name = m_data.Attributes["name"].Value;
            if (m_data.HasChildNodes) //root category
            {
                //load the subcategory from the armory - use the attribute "id" to find the right page
                //m_data2 is not used - get the remaining data from the internet
                String xml = Provider.GetFile(m_filename + "&c=" + m_data.Attributes["id"].Value);
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(xml);

                XmlNodeList achievements = xmlDoc.SelectNodes(XPATH_ACHIEVEMENT_ROOT_ACHIEVEMENTS);
                _Achievements(achievements);
                XmlNodeList subcategories = xmlDoc.SelectNodes(XPATH_ACHIEVEMENT_CATEGORIES);
                XmlNodeList titles = m_data.SelectNodes(XPATH_ACHIEVEMENT_CATEGORY_TITLES);
                _Subcategories(subcategories, titles);
            }
            else if(m_data2 != null)
            {
                //m_data2 contains the actual achievements
                //seems there are no sub categories when we have a subcategory
                XmlNodeList list = m_data2.SelectNodes(XPATH_ACHIEVEMENT_SUBCATEGORY_ACHIEVEMENTS);
                _Achievements(list);

            }
        }
        private void _Subcategories(XmlNodeList list, XmlNodeList titles)
        {
            //handle all sub categories
            if (list.Count != titles.Count)
                throw new ArgumentException("different sizes on the lists");
            for (int i = 0; i < list.Count; i++)
            {
                AchievementsCategory cat = new AchievementsCategory(titles[i], list[i]);
                cat.Load();
                m_categories.Add(cat);
            }
        }
        private void _Achievements(XmlNodeList list)
        {
            //handle all achievements
            foreach (XmlNode node in list)
            {
                Achievement ach = new Achievement(node);
                m_achievements.Add(ach);
            }
        }

        private int m_total = 0;
        public Int32 AchievementsTotal
        {
            get
            {
                if (m_total == 0)
                {
                    foreach (AchievementsCategory category in m_categories)
                        m_total += category.AchievementsTotal;
                    m_total += m_achievements.Count;
                }
                return m_total;
            }
        }
        public Int32 AchievementsEarned
        {
            get;
            private set;
        }
        public Int32 PointsTotal
        {
            get;
            private set;
        }
        public Int32 PointsEarned
        {
            get;
            private set;
        }

        private List<AchievementsCategory> m_categories = new List<AchievementsCategory>();
        public List<AchievementsCategory> Categories
        {
            get
            {
                return m_categories;
            }
        }

        private List<Achievement> m_achievements = new List<Achievement>();
        public List<Achievement> Achievements
        {
            get
            {
                return m_achievements;
            }
        }
        public String Name
        {
            get;
            private set;
        }
    }
    public class Achievement
    {
        public Achievement() { }
        public Achievement(XmlNode node) { }
    }
}
